using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Media;
using GoblinXNA;
using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Generic;
using GoblinXNA.Device.Vision.Marker;
using GoblinXNA.Graphics;
using GoblinXNA.Graphics.Geometry;
using GoblinXNA.Physics.Matali;
using GoblinXNA.SceneGraph;
using GoblinXNA.UI;
using GoblinXNA.UI.UI2D;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Color = Microsoft.Xna.Framework.Color;
using Matrix = Microsoft.Xna.Framework.Matrix;

using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Vision;
using GoblinXNA.Device.Vision.Marker;

//using Nuclex.Fonts;

namespace SplashOn_PhoneLib
{
    public class SplashOn_Phone_Main
    {
        SpriteFont sampleFont;
        SpriteFont uiFont;
        SpriteFont textFont;
        SpriteBatch spriteBatch;



        Scene scene;

        MarkerNode groundMarkerNode;
        TransformNode groundNode;
        IGraphicsDeviceService serviceCopy;
        SplashOn_Shooting splashon_shooting;

        Viewport viewport;
        RenderTarget2D renderTarget;
        Rectangle renderTargetRect;
        CameraNode cameraNode;

        // Base Rectangle Bar
        public Rectangle baseRectangle;
        Texture2D helpTexture, helpiconTexture;
        Rectangle[] screenRect = new Rectangle[4];
        String[] screenDisplay = new String[4];

        TouchInput touchInput;

        SoundEffect bounceSound;
        SoundEffect splashSound;
        String label = "Init";
        float objectRotation = 0;
        String selectedObjectName = "Torus";
        int screenCounter = 0;

        TransformNode boxCameraTransNode;
        TransformNode boxScreenTransNode;

        public SplashOn_Wayfinding wayfinding = null;
        public SplashOn_WelcomeScreen splashon_welcome = new SplashOn_WelcomeScreen();
        SpriteFont displayFont;
        SpriteFont displayFontBold;
        public static int int_highlight = -1;
        bool[] if_int_highlight = new bool[4];

        public SplashOn_Phone_Main() { }

        public Texture2D VideoBackground
        {
            get { return scene.BackgroundTexture; }
            set { scene.BackgroundTexture = value; }
        }

        public void Initialize(IGraphicsDeviceService service, ContentManager content,
                VideoBrush videoBrush, bool isStaticMarker)
        {
            viewport = new Viewport(80, 0, 640, 480);
            viewport.MaxDepth = service.GraphicsDevice.Viewport.MaxDepth;
            viewport.MinDepth = service.GraphicsDevice.Viewport.MinDepth;
            service.GraphicsDevice.Viewport = viewport;

            spriteBatch = new SpriteBatch(service.GraphicsDevice);
            serviceCopy = service;
            // Initialize the GoblinXNA framework
            State.InitGoblin(service, content, "");

            LoadContent(content);
            State.ThreadOption = (ushort)ThreadOptions.MarkerTracking;

            // Initialize the scene graph
            scene = new Scene();
            scene.BackgroundColor = Color.Black;

            // Important note about Physics. If you're not rendering at 30fps, 
            // your engine MUST take this into account by both increasing gravity AND
            // reducing the timestep from 1/30f to something less. 
            scene.PhysicsEngine = new MataliPhysics();
            scene.PhysicsEngine.Gravity = 400;
            scene.PhysicsEngine.GravityDirection = -Vector3.UnitZ;
            ((MataliPhysics)scene.PhysicsEngine).SimulationTimeStep = 1 / 20f;

            splashon_shooting = new SplashOn_Shooting();
            splashon_welcome.Initialize();

            // Set up the lights used in the scene
            CreateLights();

            CreateCamera();

            InitializeViewport();
            wayfinding = new SplashOn_Wayfinding(viewport, scene);

            SetupMarkerTracking(videoBrush, isStaticMarker);

            CreateObjects();

            touchInput = new TouchInput();
            List<TouchEventType> touchGestures = new List<TouchEventType>();
            // There are far more gestures than DoubleTap. 
            // Experiment by finding more TouchEventTypes to implement.
            touchGestures.Add(TouchEventType.DoubleTap);
            // Important. TouchInput must be initialized before use. 
            // Otherwise, it will not be happy. And neither will you.
            touchInput.Initialize(touchGestures);
            //       touchInput.DoubleTapEvent += new HandleDoubleTap(touchInput_DoubleTapEvent);            


            //State.ShowNotifications = true;
            Notifier.Font = sampleFont;

            //State.ShowFPS = true;
            System.Diagnostics.Debug.WriteLine(" INITITII ");
        }

        private void InitializeViewport()
        {
            PresentationParameters pp = State.Device.PresentationParameters;
            renderTarget = new RenderTarget2D(State.Device, viewport.Width, viewport.Height, false,
                SurfaceFormat.Color, pp.DepthStencilFormat);

            renderTargetRect = new Rectangle(0, 0, viewport.Width, viewport.Height);
        }

        public void swtichToWayfinding()
        {
            DebugHelper.w("swtichToWayfinding");
            wayfinding.isWayfindingViewOn = true;
            wayfinding.wayfindingRenderTargetRect.Y = -viewport.Height;
        }

        public void swtichToMainScreenFromWayfinding()
        {
            wayfinding.isWayfindingViewTransitionToMain = true;
        }

        public void touchInput_wayfinding(Vector2 position)
        {
            System.Diagnostics.Debug.WriteLine(" touchInput_wayfinding ");
            DebugHelper.w(" Positin:" + position);
            if(groundNode.Children.Contains(wayfinding.wayfindingTransParentNode))
            {
                groundNode.RemoveChild(wayfinding.wayfindingTransParentNode);
            }
            wayfinding.dispose();
            Create_WayFinding_Objects(position);
        }

        private double dotProduct(Vector3 v1, Vector3 v2)
        {
            DebugHelper.w(v1.ToString() + ", " + v2.ToString());
            double d;
            d = v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;

            double modV1 = Math.Sqrt(Math.Pow(v1.X, 2) + Math.Pow(v1.Y, 2) + Math.Pow(v1.Z, 2));
            double modV2 = Math.Sqrt(Math.Pow(v2.X, 2) + Math.Pow(v2.Y, 2) + Math.Pow(v2.Z, 2));

            d = d / (modV1 * modV2);
            return d;
        }

        public void ShootSphere(Vector3 near, Vector3 far, Microsoft.Xna.Framework.Color selectedColor, String mode)
        {
            if (mode == "splash")
            {
                splashon_shooting.ShootSphere(near, far, selectedColor, groundNode, bounceSound, splashSound);
            }
            else if (mode == "shoot")
            {
                splashon_shooting.ShootObject(near, far, groundNode, bounceSound, splashSound);
            }
        }

        public void generatePowerBar(int initialTicks, String mode)
        {
            if (mode == "shoot")
            {
                Thread shootingThread = new Thread(splashon_shooting.generateShootingPowerBar);
                shootingThread.Start();
            }
            else if (mode == "splash")
            {
                Thread shootingThread = new Thread(splashon_shooting.generateSplashingPowerBar);
                shootingThread.Start();
            }
        }

        private void Create_WayFinding_Objects(Vector2 position)
        {
            wayfinding.setTarget(CalculationHelper.CalculateDistanceVector3(position));
            wayfinding.isWayfindingViewTransitionToMain = true;
            groundNode.AddChild(wayfinding.wayfindingTransParentNode);
        }

        private void CreateCamera()
        {
            // Create a camera 
            Camera camera = new Camera();
            // Put the camera at the origin
            camera.Translation = new Vector3(0, 0, 0);
            // Set the vertical field of view to be 60 degrees
            camera.FieldOfViewY = MathHelper.ToRadians(60);
            // Set the near clipping plane to be 0.1f unit away from the camera
            camera.ZNearPlane = 0.1f;
            // Set the far clipping plane to be 1000 units away from the camera
            camera.ZFarPlane = 1000;

            // Now assign this camera to a camera node, and add this camera node to our scene graph
            cameraNode = new CameraNode(camera);
            scene.RootNode.AddChild(cameraNode);

            // Assign the camera node to be our scene graph's current camera node
            scene.CameraNode = cameraNode;
        }

        private void CreateLights()
        {
            // Create a directional light source
            LightSource lightSource = new LightSource();
            lightSource.Direction = new Vector3(1, -1, -1);
            lightSource.Diffuse = Color.White.ToVector4();
            lightSource.Specular = new Vector4(0.6f, 0.6f, 0.6f, 1);

            // Create a light node to hold the light source
            LightNode lightNode = new LightNode();
            lightNode.LightSource = lightSource;

            scene.RootNode.AddChild(lightNode);
        }

        private void SetupMarkerTracking(VideoBrush videoBrush, bool isStaticMarker)
        {
            IVideoCapture captureDevice = null;

            if (isStaticMarker)
            {
                captureDevice = CameraHelper.staticCaptureDevice;
                scene.ShowCameraImage = true;
            }
            else
            {
                captureDevice = new PhoneCameraCapture(videoBrush);
                captureDevice.InitVideoCapture(0, FrameRate._30Hz, Resolution._640x480,
                    ImageFormat.B8G8R8A8_32, false);
                ((PhoneCameraCapture)captureDevice).UseLuminance = true;

                captureDevice.MarkerTrackingImageResizer = new HalfResizer();
            }

            // Add this video capture device to the scene so that it can be used for
            // the marker tracker
            DebugHelper.w("capture device height " + captureDevice.Height.ToString());
            DebugHelper.w("capture device width " + captureDevice.Width.ToString());
            scene.AddVideoCaptureDevice(captureDevice);

            // Use NyARToolkit ID marker tracker
            NyARToolkitIdTracker tracker = new NyARToolkitIdTracker();

            if (captureDevice.MarkerTrackingImageResizer != null)
                tracker.InitTracker((int)(captureDevice.Width * captureDevice.MarkerTrackingImageResizer.ScalingFactor),
                    (int)(captureDevice.Height * captureDevice.MarkerTrackingImageResizer.ScalingFactor),
                    "camera_para.dat");
            else
                tracker.InitTracker(captureDevice.Width, captureDevice.Height, "camera_para.dat");

            // Set the marker tracker to use for our scene
            scene.MarkerTracker = tracker;
        }

        private void CreateObjects()
        {
            //graphics = new GraphicsDeviceManager(this);
            baseRectangle = new Rectangle(120, GraphicsDeviceManager.DefaultBackBufferHeight - 25, 560, 25);
            screenDisplay[0] = "COLOR ";
            screenDisplay[1] = " GAME ";
            screenDisplay[2] = "OBJECT";
            screenDisplay[3] = " MAP ";

            for (int i = 0; i < 4; i++)
            {
                screenRect[i] = new Rectangle(baseRectangle.X + (i * 140), GraphicsDeviceManager.DefaultBackBufferHeight - 25, 140, 25);
                if_int_highlight[i] = false;
            }

            // Create a marker node to track a ground marker array.
            groundMarkerNode = new MarkerNode(scene.MarkerTracker, "NyARIdGroundArray.xml",
                    NyARToolkitTracker.ComputationMethod.Average);

            //Create_WayFinding_Objects(new Vector2(800/2, 480/2));
            groundNode = new TransformNode("groundNode");

            // create VirtualCanvas
            DrawHelper.creatVirtualCanvas(groundNode,
                                AppConstants.VIRTUAL_CANVAS_X_DIM,
                                AppConstants.VIRTUAL_CANVAS_Y_DIM,
                                AppConstants.VIRTUAL_CANVAS_Z_DIM,
                                AppConstants.VIRTUAL_CANVAS_TRANSPARENCY,
                                AppConstants.VIRTUAL_CANVAS_OVERLAY_X_ITEMS,
                                AppConstants.VIRTUAL_CANVAS_OVERLAY_Y_ITEMS);

            Material boxMaterial = new Material();
            boxMaterial.Diffuse = Color.Blue.ToVector4();
            boxMaterial.Ambient = Color.Blue.ToVector4();
            boxMaterial.Specular = Color.Blue.ToVector4();
            boxMaterial.SpecularPower = 10;

            GeometryNode boxForBoxCameraNode = new GeometryNode("Box1");
            boxForBoxCameraNode.Model = new Box(5);
            boxForBoxCameraNode.Material = boxMaterial;
            boxCameraTransNode = new TransformNode("boxCameraTransNode");
            boxCameraTransNode.AddChild(boxForBoxCameraNode);
            boxCameraTransNode.Translation = Vector3.Zero;

            GeometryNode boxForBoxScreenNode = new GeometryNode("Box2");
            boxForBoxScreenNode.Model = new Sphere(5, 10, 10);
            boxForBoxScreenNode.Material = boxMaterial;
            boxScreenTransNode = new TransformNode("boxScreenTransNode");
            boxScreenTransNode.AddChild(boxForBoxScreenNode);
            boxScreenTransNode.Translation = Vector3.Zero;

            //groundNode.AddChild(boxScreenTransNode);
            groundNode.AddChild(boxCameraTransNode);
            groundMarkerNode.AddChild(groundNode);
            scene.RootNode.AddChild(groundMarkerNode);
        }

        private void LoadContent(ContentManager content)
        {
            sampleFont = content.Load<SpriteFont>("Sample");
            uiFont = content.Load<SpriteFont>("UIFont");
            displayFont = content.Load<SpriteFont>("DisplayFont");
            displayFontBold = content.Load<SpriteFont>("DisplayFontBold");
            textFont = content.Load<SpriteFont>("DebugFont");
            bounceSound = content.Load<SoundEffect>("BANGGUN");
            splashSound = content.Load<SoundEffect>("waterballoon");
            helpTexture = content.Load<Texture2D>("GamePage-HelpScreen");            
            splashon_welcome.LoadContent(content);
        }

        public void Dispose()
        {
            scene.Dispose();
        }

        public void Update(TimeSpan elapsedTime, bool isActive, bool isStaticMarker)
        {
            //if (!isStaticMarker)
            //{
            //    if (counter == 0)
            //    {
            //        ((PhoneCameraCapture)scene.VideoCaptures[0]).Focus();
            //    }
            //    else if (counter == 10000)
            //    {
            //        counter = 0;
            //    }
            //    counter++;
            // 

            scene.Update(elapsedTime, false, isActive);
        }

        public void HighLightScreen(Vector2 position)
        {
            for (int i = 0; i < 4; i++)
            {
                if ((position.X >= baseRectangle.X + (i * 140) && (position.X <= baseRectangle.X + ((i + 1) * 140))) &&
                    (position.Y >= baseRectangle.Top) && (position.Y <= baseRectangle.Bottom))
                {
                    int_highlight = i;
                    break;
                }
            }

            if (int_highlight == -1)
            {
                int_highlight = -2;
            }
        }

        public void HighLightScreen(int whichScreen)
        {
            int_highlight = whichScreen;
        }

        public void Draw(TimeSpan elapsedTime)
        {
            UI2DRenderer.WriteText(new Vector2(20, 5), label, Color.Red,
                textFont, GoblinEnums.HorizontalAlignment.Center, GoblinEnums.VerticalAlignment.Top);

            State.Device.Viewport = viewport;
            State.Device.Clear(Color.Black);

            if (int_highlight == -1)
            {
                State.SharedSpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                splashon_welcome.MainScreen(displayFontBold, helpTexture, State.SharedSpriteBatch);
                State.SharedSpriteBatch.End();
            }
            else if (int_highlight == -2)
            {
                if (screenCounter < 20)
                {
                    State.SharedSpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                    splashon_welcome.OpenPage(displayFontBold, helpTexture, State.SharedSpriteBatch, screenCounter);
                    State.SharedSpriteBatch.End();
                    screenCounter++;
                }
                else
                    int_highlight = 1;
            }
            else
            {
                if (wayfinding.isWayfindingViewOn)
                {
                    if (groundMarkerNode.Children.Contains(groundNode))
                    {
                        groundMarkerNode.RemoveChild(groundNode);
                        scene.RootNode.AddChild(groundNode);
                    }
                    wayfinding.updateWayfindingView(scene, groundNode, viewport, elapsedTime);
                }
                else
                {
                    scene.SceneRenderTarget = renderTarget;
                    scene.BackgroundColor = Color.Black;
                    scene.BackgroundBound = renderTargetRect;
                    scene.CameraNode = cameraNode;
                    scene.BackgroundTexture = VideoBackground;
                    if (!groundMarkerNode.Children.Contains(groundNode))
                    {
                        scene.RootNode.RemoveChild(groundNode);
                        groundMarkerNode.AddChild(groundNode);
                    }
                    scene.Draw(elapsedTime, false);

                    renderTargetRect.X += viewport.X;
                    State.Device.SetRenderTarget(null);
                    State.Device.Clear(Color.Black);
                    State.SharedSpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                    State.SharedSpriteBatch.Draw(renderTarget, renderTargetRect, Color.White);

                    Texture2D whiteRectangle = new Texture2D(serviceCopy.GraphicsDevice, 1, 1);
                    whiteRectangle.SetData(new[] { Color.White });

                    for (int i = 0; i < 7; i++)
                    {
                        State.SharedSpriteBatch.Draw(whiteRectangle, new Rectangle(110, 50 + i * 19, 50, 15),
                                splashon_shooting.getSplashingBarColors()[6 - i]);
                    }

                    for (int i = 0; i < 7; i++)
                    {
                        State.SharedSpriteBatch.Draw(whiteRectangle, new Rectangle(630, 50 + i * 19, 50, 15),
                                splashon_shooting.getShootingBarColors()[6 - i]);
                    }                    

                    if ((Objects.selectedObjectGeometryNode == null &&
                        selectedObjectName != "Torus"))
                    {
                        selectedObjectName = "Torus";
                        splashon_welcome.setObject(selectedObjectName);
                    }
                    else if (Objects.selectedObjectGeometryNode != null)
                    {
                        if (Objects.selectedObjectGeometryNode.Name == "Torus" &&
                         selectedObjectName != "Torus")
                        {
                            selectedObjectName = "Torus";
                            splashon_welcome.setObject(selectedObjectName);
                        }
                        else if (Objects.selectedObjectGeometryNode.Name == "Cylinder" &&
                            selectedObjectName != "Cylinder")
                        {
                            selectedObjectName = "Cylinder";
                            splashon_welcome.setObject(selectedObjectName);
                        }
                        else if (Objects.selectedObjectGeometryNode.Name == "Cone" &&
                            selectedObjectName != "Cone")
                        {
                            selectedObjectName = "Cone";
                            splashon_welcome.setObject(selectedObjectName);
                        }
                    }
                    if (objectRotation > 100000)
                        objectRotation = 0;
                    objectRotation += 0.1f;                    
                    splashon_welcome.createObjects(objectRotation);
                    splashon_welcome.createSplash();
                    
                    State.SharedSpriteBatch.End();

                    splashon_welcome.BaseDisplay(int_highlight);

                    renderTargetRect.X -= viewport.X;
                }

                if (groundMarkerNode.MarkerFound)
                {
                    Vector3 cameraLookingAt = new Vector3(groundMarkerNode.WorldTransformation.Translation.X,
                        groundMarkerNode.WorldTransformation.Translation.Y, -5);
                    boxCameraTransNode.Translation = -cameraLookingAt;

                    if (wayfinding.isWayfindingOn && wayfinding.update(-cameraLookingAt))
                    {
                        groundNode.RemoveChild(wayfinding.wayfindingTransParentNode);
                        wayfinding.dispose();
                        wayfinding.isWayfindingOn = false;
                    }
                }
            }
        }

        public Matrix getGroundMarker()
        {
            return groundMarkerNode.WorldTransformation;
        }

        public Matrix getViewMatrix()
        {
            return State.ViewMatrix;
        }

        public Matrix getProjectionMatrix()
        {
            return State.ProjectionMatrix;
        }

        public void showMainHelp()
        {
            State.SharedSpriteBatch.Begin();
            splashon_welcome.MainScreen(displayFontBold, helpTexture, State.SharedSpriteBatch);
            State.SharedSpriteBatch.End();
        }
   
    }
}

